package com.zkyc.framework.common.aop;

import com.alibaba.fastjson.JSONObject;
import com.zkyc.framework.common.Enum.LogType;
import com.zkyc.framework.common.annotation.Log;
import com.zkyc.framework.common.constant.Constant;
import com.zkyc.framework.common.constant.NumberConstant;
import com.zkyc.framework.common.mapper.SystemLogMapper;
import com.zkyc.framework.common.pojo.SystemLog;
import com.zkyc.framework.common.pojo.User;
import com.zkyc.framework.common.utils.WebsiteUtil;
import com.zkyc.framework.common.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;

/**
 * @author bing.bai
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Autowired(required = false)
    private JedisPool jedisPool;

    @Autowired
    private SystemLogMapper systemLogMapper;

    @Pointcut("@annotation(com.zkyc.framework.common.annotation.Log)")
    public void logAop() {
    }

    @AfterReturning(returning = "rvt", pointcut = "logAop()")
    public void after(JoinPoint joinPoint, ResultVO rvt) {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        Log logAnnotation = method.getAnnotation(Log.class);
        User user;
        String token;
        Jedis resource = null;
        if (sra != null) {
            HttpServletRequest request = sra.getRequest();
            try {
                resource = jedisPool.getResource();
                String os = request.getHeader("os");
                SystemLog systemLog = new SystemLog();
                systemLog.setIp(getRemoteHost(request));
                systemLog.setOperateDate(new Date());
                if (logAnnotation.type() == LogType.登入) {
                    HashMap data = (HashMap) rvt.getData();
                    if (!rvt.isSuccess()) {
                        return;
                    }
                    systemLog.setOperateType(logAnnotation.type() + "");
                    token = (String) data.get("token");
                    String redisKey = Constant.REDIS_PREFIX + "TOKEN_" + token;
                    String userString = resource.get(redisKey);
                    user = JSONObject.parseObject(userString, User.class);
                } else {
                    //得到header中的信息
                    token = request.getHeader("accessToken");
                    String redisKey = Constant.REDIS_PREFIX + "TOKEN_" + token;
                    String userString = resource.get(redisKey);
                    user = JSONObject.parseObject(userString, User.class);
                    Object[] args = joinPoint.getArgs();
                    System.out.println(JSONObject.toJSONString(args));
                    if ("POST".equals(request.getMethod())) {
                        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(args[0]));
                        handleOperateDetail(logAnnotation, jsonObject, rvt, systemLog, args);
                        Integer websiteId = jsonObject.getInteger("websiteId");
                        System.out.println("websiteId为++++++" + websiteId);
                        systemLog.setWebsiteId(websiteId);
                    }
                    if ("GET".equals(request.getMethod())) {
                        JSONObject jsonObject = new JSONObject();
                        handleOperateDetail(logAnnotation, jsonObject, rvt, systemLog, args);
                    }
                }
                String websiteId = WebsiteUtil.getWebsiteId();
                if (StringUtils.isNotBlank(websiteId) && !"null".equals(websiteId)) {
                    systemLog.setWebsiteId(Integer.parseInt(websiteId));
                }
                systemLog.setOperatorUsername(user.getUsername());
                systemLog.setOperateOs(os);
                systemLogMapper.insert(systemLog);
                log.info("日志插入成功");
            } catch (Exception e) {

            } finally {
                resource.close();
            }

        }
    }

    private void handleOperateDetail(Log logAnnotation, JSONObject jsonObject, ResultVO rvt, SystemLog systemLog, Object[] args) {
        switch (logAnnotation.type()) {
            case 内容管理稿件发布:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("稿件管理");
                systemLog.setOperateDetail("新增稿件,稿件ID" + rvt.getData());
                break;
            case 新增组织:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("组织管理");
                systemLog.setOperateDetail("新增组织,组织名称" + jsonObject.getString("organizationName"));
                break;
            case 增加下级:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("组织管理");
                systemLog.setOperateDetail("增加下级,下级名称" + jsonObject.getString("centerName"));
                break;
            case 新建用户:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("用户管理");
                systemLog.setOperateDetail("新建用户,用户名称" + jsonObject.getString("username"));
                break;
            case 新建角色:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("角色管理");
                systemLog.setOperateDetail("新建角色,角色名称" + jsonObject.getString("roleName"));
                break;
            case 新建站点:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("站点管理");
                systemLog.setOperateDetail("新建站点,站点名称" + jsonObject.getString("websiteName"));
                break;
            case 内容管理稿件编辑:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("稿件管理");
                systemLog.setOperateDetail("编辑稿件,稿件ID" + jsonObject.getString("id"));
                break;
            case 推荐稿件:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("稿件管理");
                systemLog.setOperateDetail("推荐稿件,稿件ID" + jsonObject.getString("contentId"));
                break;
            case 移除稿件:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("稿件管理");
                systemLog.setOperateDetail("移除稿件,稿件ID" + jsonObject.getString("contentId"));
                break;
            case 保存研究院:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("组织管理");
                systemLog.setOperateDetail("保存研究院，研究院名称" + jsonObject.getString("organizationName"));
                break;
            case 保存中心:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("组织管理");
                systemLog.setOperateDetail("保存中心，中心名称" + jsonObject.getString("centerName"));
                break;
            case 内容管理稿件删除:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("稿件管理");
                systemLog.setOperateDetail("移除稿件,稿件ID" + jsonObject.getString("contentId"));
                break;
            case 编辑用户:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("用户管理");
                systemLog.setOperateDetail("编辑用户,用户名称" + systemLogMapper.selectUser(jsonObject.getString("id")).getUsername());
                break;
            case 编辑角色:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("角色管理");
                systemLog.setOperateDetail("编辑角色,角色名称" + systemLogMapper.selectRole(jsonObject.getString("id")).getRoleName());
                break;
            case 编辑站点:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("站点管理");
                systemLog.setOperateDetail("编辑站点,站点名称" + jsonObject.getString("websiteName"));
                break;
            case 修改密码:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("用户管理");
                systemLog.setOperateDetail("修改密码,用户账号" + jsonObject.getString("username"));
                break;
            case 重置密码:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("用户管理");
                systemLog.setOperateDetail("重置密码,用户账号" + systemLogMapper.selectUser(args[0].toString()).getUsername());
                break;
            case 启用禁用用户:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("用户管理");
                if (args[1].equals(NumberConstant.NUMBER_1)) {
                    systemLog.setOperateDetail("启用用户,用户名称" + systemLogMapper.selectUser(args[0].toString()).getUsername());
                } else {
                    systemLog.setOperateDetail("禁用用户,用户名称" + systemLogMapper.selectUser(args[0].toString()).getUsername());
                }
                break;
            case 启用禁用角色:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("角色管理");
                if (args[1].equals(NumberConstant.NUMBER_1)) {
                    systemLog.setOperateDetail("启用角色,角色名称" + systemLogMapper.selectRole(args[0].toString()).getRoleName());
                } else {
                    systemLog.setOperateDetail("禁用角色,角色名称" + systemLogMapper.selectRole(args[0].toString()).getRoleName());
                }
                break;
            case 启用禁用站点:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("站点管理");
                if (args[1].equals(NumberConstant.NUMBER_1)) {
                    systemLog.setOperateDetail("启用站点,站点名称" + systemLogMapper.selectWebsite(args[0].toString()).getWebsiteName());
                } else {
                    systemLog.setOperateDetail("禁用站点,站点名称" + systemLogMapper.selectWebsite(args[0].toString()).getWebsiteName());
                }
                break;
            case 发布栏目:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("栏目管理");
                if (StringUtils.isNotBlank(jsonObject.getString("enName"))) {
                    systemLog.setOperateDetail("发布栏目，栏目名称" + jsonObject.getString("columnName") + "/" + jsonObject.getString("enName"));
                } else {
                    systemLog.setOperateDetail("发布栏目，栏目名称" + jsonObject.getString("columnName"));
                }
                break;
            case 修改栏目:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("栏目管理");
                if (StringUtils.isNotBlank(jsonObject.getString("enName"))) {
                    systemLog.setOperateDetail("修改栏目名称，修改后栏目名称" + jsonObject.getString("columnName") + "/" + jsonObject.getString("enName"));
                } else {
                    systemLog.setOperateDetail("修改栏目名称，修改后栏目名称" + jsonObject.getString("columnName"));
                }
                break;
            case 修改模块:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("栏目管理");
                if (StringUtils.isNotBlank(jsonObject.getString("enName"))) {
                    systemLog.setOperateDetail("修改栏目名称，修改后栏目名称" + jsonObject.getString("moudleName") + "/" + jsonObject.getString("enName"));
                } else {
                    systemLog.setOperateDetail("修改栏目名称，修改后栏目名称" + jsonObject.getString("moudleName"));
                }
                break;
            case 栏目数据发布:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("栏目管理");
                systemLog.setOperateDetail("新增栏目数据,ID" + jsonObject.getString("id"));
                break;
            case 栏目数据编辑:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("栏目管理");
                systemLog.setOperateDetail("编辑栏目数据,ID" + jsonObject.getString("id"));
                break;
            case 推荐栏目数据:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("栏目管理");
                systemLog.setOperateDetail("推荐栏目数据,ID" + jsonObject.getString("id"));
                break;
            case 移除栏目数据:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("栏目管理");
                systemLog.setOperateDetail("移除栏目数据,ID" + jsonObject.getString("id"));
                break;
            case 栏目数据删除:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("栏目管理");
                systemLog.setOperateDetail("删除栏目数据,ID" + args[0].toString());
                break;
            case 删除研究院:
                systemLog.setOperateType(Constant.DELETE);
                systemLog.setOperateMoudle("组织管理");
                systemLog.setOperateDetail("删除研究院，研究院名称" + rvt.getData());
                break;
            case 删除中心:
                systemLog.setOperateType(Constant.DELETE);
                systemLog.setOperateMoudle("组织管理");
                systemLog.setOperateDetail("删除中心,中心名称" + rvt.getData());
                break;
            case 新增协会:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("协会管理");
                systemLog.setOperateDetail("新增协会,协会名称" + jsonObject.getString("centerName"));
                break;
            case 编辑协会:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("协会管理");
                systemLog.setOperateDetail("编辑协会,协会名称" + systemLogMapper.selectAssociation(jsonObject.getString("id")).getCenterName());
                break;
            case 新增活动:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("活动管理");
                systemLog.setOperateDetail("新增活动,活动名称" + jsonObject.getString("titleName"));
                break;
            case 编辑活动:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("活动管理");
                systemLog.setOperateDetail("编辑活动,活动名称" + systemLogMapper.selectActivity(jsonObject.getString("id")).getTitleName());
                break;
            case 新增招聘宣讲:
                systemLog.setOperateType(Constant.ADD);
                systemLog.setOperateMoudle("招聘宣讲");
                systemLog.setOperateDetail("新增招聘宣讲,宣讲名称" + jsonObject.getString("meetingName"));
                break;
            case 编辑招聘宣讲:
                systemLog.setOperateType(Constant.UPDATE);
                systemLog.setOperateMoudle("招聘宣讲");
                systemLog.setOperateDetail("编辑招聘宣讲,宣讲名称" + jsonObject.getString("meetingName"));
                break;
        }

    }

    /**
     * 获取目标主机的ip
     */
    private static String getRemoteHost(HttpServletRequest request) {
        String Xip = request.getHeader("X-Real-IP");
        String XFor = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotBlank(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = XFor.indexOf(",");
            if (index != -1) {
                return XFor.substring(0, index);
            } else {
                return XFor;
            }
        }
        XFor = Xip;
        if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
            return XFor;
        }
        if (StringUtils.isBlank(XFor) || "unKnown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unKnown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unKnown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isBlank(XFor) || "unKnown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isBlank(XFor) || "unKnown".equalsIgnoreCase(XFor)) {
            XFor = request.getRemoteAddr();
        }

        return XFor;
    }
}
